package scenic.path;

import java.awt.Rectangle;

import scenic.Util;
import scenic.geom.Affine2;
import scenic.geom.Double2;

/**
 * This class defines an elliptical arc. This class does not 
 * define the start point of the arc. The start point is the 
 * end point of the previous segment.
 */
public class ArcSegment extends CurvedSegment {
	private double xRadius;
	private double yRadius;
	private double rotation;
	private double startAngle;
	private double stopAngle;
	
	/**
	 * Creates an elliptic arc segment with the given parameters.
	 * 
	 * @param xRadius x radius of the ellipse.
	 * @param yRadius y radius of the ellipse.
	 * @param rotation rotation of the ellipse in degrees.
	 * @param startAngle start angle of the arc in degrees.
	 * @param stopAngle stop angle of the arc in degrees.
	 */
	public ArcSegment(double xRadius, double yRadius, double rotation, 
			double startAngle, double stopAngle) {
		this.xRadius = xRadius;
		this.yRadius = yRadius;
		this.rotation = rotation;
		this.startAngle = startAngle;
		this.stopAngle = stopAngle;
	}
	
	/**
	 * Gets the x radius of the ellipse.
	 */
	public double getXRadius() {
		return xRadius;
	}

	/**
	 * Gets the y radius of the ellipse.
	 */
	public double getYRadius() {
		return yRadius;
	}

	/**
	 * Gets the rotation of the ellipse in degrees.
	 */
	public double getRotation() {
		return rotation;
	}

	/**
	 * Gets the start angle of the arc in degrees.
	 */
	public double getStartAngle() {
		return startAngle;
	}

	/**
	 * Gets the stop angle of the arc in degrees.
	 */
	public double getStopAngle() {
		return stopAngle;
	}

	public Double2 calcPoint(double t, Double2 position) {
		Double2 p = new Double2();
		double angle = Math.toRadians(startAngle + (stopAngle - startAngle) * t);
		double x, y;
		double sinr = Math.sin(Math.toRadians(rotation));
		double cosr = Math.cos(Math.toRadians(rotation));
		
		x = (Math.cos(angle) - Math.cos(Math.toRadians(startAngle))) * xRadius;
		y = (Math.sin(angle) - Math.sin(Math.toRadians(startAngle))) * yRadius;

		p.x = position.x + cosr * x - sinr * y;
		p.y = position.y + sinr * x + cosr * y;			
		
		return p;
	}
	
	/**
	 * Calculates the point along the arc, when the center of the ellipse
	 * is thought to be at (0, 0). 
	 * 
	 * @param t the place along the arc (must be inside the rangle [0, 1]).
	 * @return the point.
	 */
	public Double2 calcRelativePoint(double t) {
		Double2 p = new Double2();
		double angle = Math.toRadians(startAngle + (stopAngle - startAngle) * t);
		double x, y;
		double sinr = Math.sin(Math.toRadians(rotation));
		double cosr = Math.cos(Math.toRadians(rotation));
		
		x = Math.cos(angle) * xRadius;
		y = Math.sin(angle) * yRadius;

		p.x = cosr * x - sinr * y;
		p.y = sinr * x + cosr * y;			
		
		return p;
	}
	
	public void getBounds(Affine2 transform, Rectangle r, Double2 position) {
		Rectangle a = new Rectangle();
		double x, y;
		
		x = position.x - Math.cos(Math.toRadians(startAngle)) * xRadius;
		y = position.y - Math.sin(Math.toRadians(startAngle)) * yRadius;
		
		a.x = (int)(x - xRadius);
		a.y = (int)(y - yRadius);
		a.width = (int)Math.ceil(x + xRadius) - a.x;
		a.height = (int)Math.ceil(y + yRadius) - a.y;
		
		a = Affine2.transform(Affine2.multiply(transform, 
				Affine2.rotate(rotation)), a);
		
		Util.combine(r, a);
	}	
}
